package dict

import (
	"d-serv-go/server/core/bean"
	"d-serv-go/server/core/cache"
	"d-serv-go/server/core/config"
	"d-serv-go/server/core/consts"
	"d-serv-go/server/core/db"
	"d-serv-go/server/core/log"
	"d-serv-go/server/core/org"
	"d-serv-go/server/core/serv"
	"d-serv-go/server/core/util"
	strutils "d-serv-go/server/core/util/stringutils"
	"math"
	"os"
	"strings"
)

type dictMgr struct {
}

type DictListener interface {
	Call(dict *bean.Bean, item *bean.Bean)
}

func NewDictMgr() *dictMgr {
	return &dictMgr{}
}

func (d *dictMgr) GetName(dictId string, code string) string {
	item := d.GetItem(dictId, code)
	if item != nil {
		return item.GetStr("NAME")
	} else {
		return code
	}
}

func (d *dictMgr) GetItem(dictId string, code string) *bean.Bean {
	dict := d.GetDict(dictId)

	if dict != nil {
		itemsBean := d.GetItemMap(dict)
		if itemsBean != nil && itemsBean.Contains(code) {
			return itemsBean.GetBean(code)
		}
	}
	return nil
}

func (d *dictMgr) GetItemMap(dict *bean.Bean) *bean.Bean {
	ctx := db.Ctx()
	cmpy := bean.If(dict.GetInt("S_PUBLIC") == consts.YES_INT, consts.PUBLIC_CMPY, ctx.GetCmpy()).(string)
	dictBean := d.GetItemCmpyBean(dict, cmpy)
	return dictBean.GetBean(consts.CHILD_NODE_MAP)
}

func (d *dictMgr) GetCmpyItemMap(dict *bean.Bean, cmpy string) *bean.Bean {
	dictBean := d.GetItemCmpyBean(dict, cmpy)
	return dictBean.GetBean(consts.CHILD_NODE_MAP)
}

func (d *dictMgr) GetItemCmpyBean(dict *bean.Bean, cmpy string) *bean.Bean {
	return d.getItemCmpyBean2(dict, cmpy)
}

func (d *dictMgr) getItemCmpyBean2(dict *bean.Bean, cmpy string) *bean.Bean {
	var cmpyBean *bean.Bean
	var bCache bool
	// 字典设置了禁用缓存或者指定了扩展where条件,不进行缓存处理
	if dict.GetInt("DICT_LOAD_TYPE") == consts.NO_INT { // =======临时使用的字典  || !context.isEmpytyThread(THREAD_DICT_EXT_WHERE)
		bCache = false
	} else {
		bCache = true
	}
	if bCache {
		if dict.IsNotEmpty("DICT_SRC_ID") { // 启用了引用数据，则获取对应字典的数据
			dictSrc := d.GetDict(dict.GetStr("DICT_SRC_ID"))
			if dictSrc != nil {
				cmpyBean = d.GetItemCmpyBean(dictSrc, cmpy)
			}
		} else {
			if p, ok := cache.CacheMgr.Get(cmpy, consts.CACHE_PRE_CMPY+dict.GetId()).(*bean.Bean); ok {
				cmpyBean = p
			}
		}
	}
	if cmpyBean == nil { // 数据没有初始化
		cmpyBean = d.loadItem(dict, cmpy)
		if bCache {
			if cmpyBean != nil {
				cache.CacheMgr.Set(cmpy, cmpyBean, consts.CACHE_PRE_CMPY+dict.GetId()) // 设置缓存10年
			} else {
				log.Error("注意：外部字典【" + dict.GetId() + "】加载后为nil，不能缓存null，请检查！！！！！！！！！！！！！！！")
			}
		}
		// 监控外部字典的加载
		// monitDictLoadCount(dict);
	}
	return cmpyBean
}

func (d *dictMgr) loadItem(dict *bean.Bean, cmpyCode string) *bean.Bean {
	var cmpyBean *bean.Bean
	if dict.GetInt("DICT_IS_INNER") == consts.YES_INT { //内部字典(必须为公共字典），执行内部初始化
		cmpyBean = bean.NewBean("")
		itemList := dict.GetBeans(consts.TABLE_DICT_ITEM)
		itemMap := bean.NewBean("")
		list := []*bean.Bean{}
		for _, item := range itemList {
			nItem := item.Clone()
			nItem.Set("ID", item.GetStr("ITEM_CODE"))
			nItem.Set("NAME", item.GetStr("ITEM_NAME"))
			nItem.Set("PID", item.GetStr("ITEM_PCODE"))
			itemMap.Set(nItem.GetStr("ID"), nItem)
			if nItem.GetInt("ITEM_FLAG") != consts.NO_INT { //列表只显示有效的数据
				//if (!Context.isEmpytyThread(THREAD_DICT_EXT_WHERE)) {
				//	if (Lang.isTrueScript(
				//		ServUtils.replaceSysAndData(Context.getThreadStr(THREAD_DICT_EXT_WHERE), nItem))) {
				//		list.add(nItem);
				//	}
				//} else {
				list = append(list, nItem)
				//}
			}
		}                                                     //end for
		if dict.GetInt("DICT_TYPE") == consts.DIC_TYPE_TREE { //树形处理
			cmpyBean.Set(consts.CHILD_NODE, d.toTree(dict, itemMap, true))
		} else { //列表
			cmpyBean.Set(consts.CHILD_NODE, list)
		}
		cmpyBean.Set(consts.CHILD_NODE_MAP, itemMap)
	} else { //外部字典，执行外部初始化
		cmpyBean = d.loadDictItem(dict, cmpyCode)
	}
	return cmpyBean
}

func (d *dictMgr) toTree(dict *bean.Bean, itemList *bean.Bean, autoFlag bool) []*bean.Bean {
	topList := []*bean.Bean{}
	leaf := bean.If(autoFlag, consts.YES, consts.NO).(string)
	for _, key := range itemList.Keys() {
		item := itemList.GetBean(key)
		item.Set("LEAF", leaf)
		if dict.Contains(consts.DICT_CLASS) {
			// 字典上的自定义类
			if dict.Contains(consts.DICT_CLASS) {
				dict.Get(consts.DICT_CLASS).(DictListener).Call(dict, item)
			}
		}
		if item.GetInt("FLAG") == consts.NO_INT { //忽略被禁用的数据
			continue
		}
		if !item.IsEmpty("PID") {
			pItem := itemList.GetBean(item.GetStr("PID"))
			if pItem != nil {
				var pList []*bean.Bean
				if pItem.Contains(consts.CHILD_NODE) {
					pList = pItem.GetBeans(consts.CHILD_NODE)
				} else {
					pList = make([]*bean.Bean, 0)
					pItem.Set("LEAF", consts.NO) //设置为非叶子节点
				}
				pList = append(pList, item)
				pItem.Set(consts.CHILD_NODE, pList)
			} else {
				topList = append(topList, item)
			}
		} else {
			topList = append(topList, item)
		}
	}
	return topList
}

func (d *dictMgr) GetDict(dictId string) *bean.Bean {
	if len(dictId) == 0 {
		return nil
	}

	dictBean := cache.CacheMgr.Get(dictId, consts.CACHE_DICT)
	// 如果在缓存中取不到，则重新从数据库中读取
	if dictBean == nil {
		dict1, err := d.GetDictDef(dictId)
		if err != nil {
			return nil
		}

		return dict1
	}
	return dictBean.(*bean.Bean)
}

func (d *dictMgr) GetDictDef(dictId string) (*bean.Bean, error) {
	return getDictDefByFile(dictId)
}

func (d *dictMgr) loadDictItem(dict *bean.Bean, cmpyCode string) *bean.Bean {
	cmpyBean := bean.NewBean("")
	ctx := db.Ctx()
	var dataList []*bean.Bean
	itemList := d.GetDictItemList(dict, cmpyCode)
	// 判断是否有子字典定义，如果有，装载子字典定义；只支持树状字典增加子字典项;子字典必须为叶子字典
	if dict.GetInt(consts.COL_DICT_TYPE) == consts.DIC_TYPE_TREE {
		if len(dict.GetStr("DICT_CHILD_ID")) > 0 {
			dataList = d.toTree(dict, itemList, false) //强制父树全部给枝节点
			// 如果有子字典，取字典定义
			childDict := d.GetDict(dict.GetStr("DICT_CHILD_ID"))
			// 判断子字典是否为叶子字典，并且配置了父字典字段ID
			if len(childDict.GetStr(consts.COL_DICT_F_PARENT)) > 0 {
				var extWhere string
				if !ctx.IsEmpyty(consts.THREAD_DICT_EXT_WHERE) { //忽略父字典自定义过滤条件
					extWhere = ctx.GetStr(consts.THREAD_DICT_EXT_WHERE)
					ctx.Remove(consts.THREAD_DICT_EXT_WHERE) //清除父的自定义过滤
				}
				childBeanList := d.GetDictItemList(childDict, cmpyCode)
				itemList.SetMap(d.GetCmpyItemMap(childDict, cmpyCode).GetMap())
				for _, key := range childBeanList.Keys() {
					childBean := childBeanList.GetBean(key)
					if childBean.Get("PID") != nil { // 根据PID把子字典拼装到父字典树
						parentBean := itemList.GetBean(childBean.GetStr("PID"))
						if parentBean != nil {
							child := parentBean.GetBeans(consts.CHILD_NODE)
							if child == nil {
								child = make([]*bean.Bean, 0)
								parentBean.Set(consts.CHILD_NODE, child)
							}
							childBean.Set("LEAF", consts.YES) //设置为叶子节点
							child = append([]*bean.Bean{childBean}, child...)
						}
					}
				}
				if len(extWhere) > 0 { //恢复父的自定义过滤
					ctx.SetStr(consts.THREAD_DICT_EXT_WHERE, extWhere)
				}
			} //end if
		} else {
			dataList = d.toTree(dict, itemList, true) //自动判断叶子根节点
		} //end DICT_CHILD_ID 父子树判断
	} else {
		dataList = d.toTree(dict, itemList, true)
	} //end DIC_TYPE_TREE 树形判断
	cmpyBean.Set(consts.CHILD_NODE, dataList)
	cmpyBean.Set(consts.CHILD_NODE_MAP, itemList)
	return cmpyBean
}

func (d *dictMgr) GetDictItemList(dict *bean.Bean, cmpyCode string) *bean.Bean {
	sqlBuilder := strutils.NewStringBuilder("")
	sqlBuilder.Append("select ")
	sqlBuilder.Append(dict.GetStr(consts.COL_DICT_F_ID)).Append(" ID, ")
	sqlBuilder.Append(dict.GetStr(consts.COL_DICT_F_NAME)).Append(" NAME")
	if dict.GetInt(consts.COL_DICT_TYPE, consts.DIC_TYPE_LIST) == consts.DIC_TYPE_LEAF || dict.GetInt(consts.COL_DICT_TYPE, consts.DIC_TYPE_LIST) == consts.DIC_TYPE_TREE {
		sqlBuilder.Append(", ").Append(dict.GetStr(consts.COL_DICT_F_PARENT)).Append(" PID")
	}
	if !dict.IsEmpty("DICT_F_FLAG") {
		sqlBuilder.Append(",").Append(dict.GetStr("DICT_F_FLAG")).Append(" FLAG")
	}
	if len(dict.GetStr(consts.COL_TABLE_SELECT)) > 0 {
		sqlBuilder.Append(", ").Append(dict.GetStr(consts.COL_TABLE_SELECT))
	}

	sqlBuilder.Append(" from ").Append(dict.GetStr(consts.COL_TABLE_ID))
	sqlBuilder.Append(getDictItemListWhere(dict, cmpyCode)) //获取where设定信息

	if !dict.IsEmpty(consts.COL_TABLE_ORDER) {
		sqlBuilder.Append(" order by ").Append(dict.GetStr(consts.COL_TABLE_ORDER))
	}
	ctx := db.Ctx()
	itemList := bean.NewBean("")
	ctx.BeginTx(dict.GetStr("DICT_DATA_SOURCE"))
	defer ctx.EndTx()

	ctx.GetExecutor().Query(sqlBuilder.ToString(), nil, func(columns []*bean.Bean, data *bean.Bean) int {
		data.Remove(consts.PARAM_ROWNUM) //减小输出大小
		data.Remove(consts.KEY_ID)
		itemList.Set(data.GetStr("ID"), data)
		return 1
	})
	return itemList
}

func getDictItemListWhere(dict *bean.Bean, cmpyCode string) string {
	ctx := db.Ctx()
	sqlBuilder := strutils.NewStringBuilder("")
	sqlBuilder.Append(" where 1=1  and (")
	if len(cmpyCode) > 0 && dict.IsNotEmpty(consts.COL_DICT_F_CMPY) {
		sqlBuilder.Append("").Append(dict.GetStr(consts.COL_DICT_F_CMPY)).Append("='").Append(cmpyCode).Append("' ")
	} else {
		sqlBuilder.Append("1=1 ")
	}
	tableWhere := dict.GetStr(consts.COL_TABLE_WHERE)
	if len(tableWhere) > 0 {
		if strings.Index(tableWhere, "@@") >= 0 { //存在数据权限
			tableWhere = org.DataAclMgr.ReplaceDataAcl(tableWhere)
		}
		if strings.Index(tableWhere, "@") >= 0 { //存在变量替换
			tableWhere = db.VarMgr.ReplaceSysVar(tableWhere)
		}
	}
	sqlBuilder.Append(tableWhere).Append(") ")
	if !ctx.IsEmpyty(consts.THREAD_DICT_EXT_WHERE) { //处理自定义过滤条件（通过线程变量传递）
		sqlBuilder.Append(ctx.GetStr(consts.THREAD_DICT_EXT_WHERE))
	}
	return sqlBuilder.ToString()
}

func getDictDefByFile(dictId string) (*bean.Bean, error) {
	var (
		dictBean *bean.Bean
		err      error
	)
	sep := string(os.PathSeparator)
	fileName := config.Instance.AppDir + sep + "docs" + sep + "SY_SERV_DICT" + sep + dictId + ".json"
	if util.FileExists(fileName + "x") {
		dictBean, err = util.FromJsonFile(fileName + "x")
	} else if util.FileExists(fileName) {
		dictBean, err = util.FromJsonFile(fileName)
	}
	if dictBean != nil {
		// no imple for DICT_CLASS
		if dictBean.Contains(consts.SY_SERV_DICT_ITEM) {
			items := dictBean.GetArray(consts.SY_SERV_DICT_ITEM)
			beans := make([]*bean.Bean, 0)
			for _, item := range items {
				if m, ok := item.(map[string]interface{}); ok {
					beans = append(beans, bean.NewBean2(m))
				}
			}
			dictBean.Set(consts.SY_SERV_DICT_ITEM, beans)
		}
		cache.CacheMgr.Set(dictId, dictBean, consts.CACHE_DICT)
	}
	return dictBean, err
}

func (d *dictMgr) Contains(dictId, code string) bool {
	dict := d.GetDict(dictId)
	if dict != nil {
		nodeMap := d.GetItemMap(dict)
		if nodeMap != nil {
			return nodeMap.Contains(code)
		} else {
			return false
		}
	} else {
		return false
	}
}

func (d *dictMgr) GetTreeList(dictId, pid string, disLayer int, showPid bool) []*bean.Bean {
	var treeList []*bean.Bean
	dict := d.GetDict(dictId)
	if dict != nil {
		if len(pid) == 0 {
			pid = ""
		}
		dynaRoot := false  //动态根，缺省为false
		if len(pid) == 0 { //如果没有指定父
			if dict.IsNotEmpty("DICT_ROOT") { //且设定了动态根，用动态根
				pid = serv.ServUtils.ReplaceSysVars(dict.GetStr("DICT_ROOT"))
				dynaRoot = true //指定动态根为true
			}
		} else if showPid { //pid不为空，且包含PID作为根节点
			dynaRoot = true
		}
		cmpy := bean.If(dict.GetInt("S_PUBLIC") == consts.YES_INT, consts.PUBLIC_CMPY, db.Ctx().GetCmpy()).(string)
		itemCmpyBean := d.GetItemCmpyBean(dict, cmpy) //获取字典数据信息
		nodeMap := itemCmpyBean.GetBean(consts.CHILD_NODE_MAP)
		var dataList = make([]*bean.Bean, 0)
		if (len(pid) == 0) || !nodeMap.Contains(pid) {
			dataList = itemCmpyBean.GetBeans(consts.CHILD_NODE)
		} else if !nodeMap.Contains(pid) {
			// dataList = new ArrayList<Bean>();
		} else {
			pBean := nodeMap.GetBean(pid)
			if dynaRoot { //动态根，要包含根节点
				// dataList = new ArrayList<Bean>();
				dataList = append(dataList, pBean)
			} else { //其他情况不包含根信息
				dataList = pBean.GetBeans(consts.CHILD_NODE)
			}
		}
		if disLayer <= 0 && dict.IsEmpty("DICT_EXPRESSION") { //向下显示到末级
			treeList = dataList
		} else {
			//分级获取数据，包含当前层级
			treeList = d.recurSubList(dict, dataList, disLayer)
		}
	} else {
		treeList = make([]*bean.Bean, 0)
	}
	return treeList
}

func (d *dictMgr) recurSubList(dict *bean.Bean, treeList []*bean.Bean, layer int) []*bean.Bean {
	outList := make([]*bean.Bean, 0)
	exp := dict.GetStr("DICT_EXPRESSION")
	subExp := ""
	if dict.IsNotEmpty("DICT_CHILD_ID") {
		subDict := d.GetDict(dict.GetStr("DICT_CHILD_ID"))
		if subDict != nil {
			subExp = subDict.GetStr("DICT_EXPRESSION")
		}
	}

	for _, item := range treeList {
		out := item.Clone()
		//根据数据规则表达式确定是否包含在显示结果中
		//独立树或者父子树的枝节点判断当前字典的规则表达式
		if dict.IsEmpty("DICT_CHILD_ID") || (out.GetInt("LEAF") != consts.YES_INT) {
			if len(exp) > 0 {
				if !util.Lang.IsTrueScript(serv.ServUtils.ReplaceSysAndData(exp, out)) {
					continue
				}
			}
		} else if len(subExp) > 0 { //父子树的叶子节点判断子字典的规则表达式
			if !util.Lang.IsTrueScript(serv.ServUtils.ReplaceSysAndData(subExp, out)) {
				continue
			}
		}
		if out.Contains(consts.CHILD_NODE) {
			if layer == 1 { // 保留CHILD，前台才可以判断有没有子
				out.Set(consts.CHILD_NODE, make([]*bean.Bean, 0))
				//out.set("LEAF", Constant.NO); //设置为非叶子节点
			} else {
				subList := d.recurSubList(dict, out.GetBeans(consts.CHILD_NODE), layer-1)
				if len(subList) > 0 {
					out.Set(consts.CHILD_NODE, subList)
				} else { //没有符合条件的就清除子
					out.Remove(consts.CHILD_NODE)
				}
			}
		}
		if out.GetInt("LEAF") == consts.NO_INT && !out.Contains(consts.CHILD_NODE) {
			out.Set(consts.CHILD_NODE, make([]*bean.Bean, 0))
		}
		outList = append(outList, out)
	} //end for
	return outList
}

func (d *dictMgr) GetItemList(dict *bean.Bean, cmpy string) []*bean.Bean {
	return d.GetItemCmpyBean(dict, cmpy).GetBeans(consts.CHILD_NODE)
}

func (d *dictMgr) GetDynaItemList(dic string, paramBean *db.ParamBean) *bean.OutBean {
	//Class cls = Lang.loadClass(dic);
	//Method method = cls.getMethod("getItems", new Class[] {ParamBean.class});
	//return (Bean) method.invoke(cls.newInstance(), paramBean);
	out := bean.NewOutBean()
	return out
}

func (d *dictMgr) HandleTree(treeList []*bean.Bean, ls db.ListHandler) {
	for _, data := range treeList {
		ls(data)
		if data.Contains(consts.CHILD_NODE) {
			d.HandleTree(data.GetBeans(consts.CHILD_NODE), ls)
		}
	}
}

func (d *dictMgr) IsSingleTree(dictDef *bean.Bean) bool {
	if dictDef == nil {
		return false
	}
	return dictDef.GetInt(consts.COL_DICT_TYPE) == consts.DIC_TYPE_TREE && dictDef.IsEmpty("DICT_CHILD_ID")
}

func (d *dictMgr) GetFullNames(dictId string, codes string) string {
	if strings.Index(codes, consts.SEPARATOR) > 0 {
		cs := strings.Split(codes, consts.SEPARATOR)
		result := strutils.NewStringBuilder()
		for _, code := range cs {
			result.Append(d.getFullName(dictId, code)).Append(consts.SEPARATOR)
		}
		if len(cs) > 0 {
			result.Truncate(result.Len() - 1)
		}
		return result.ToString()
	} else {
		return d.getFullName(dictId, codes)
	}
}

func (d *dictMgr) getFullName(dictId string, code string) string {
	if len(code) == 0 {
		return code
	}
	dict := d.GetDict(dictId)
	if dict == nil {
		return code
	}
	itemMap := d.GetItemMap(dict)
	if (itemMap == nil) || (!itemMap.Contains(code)) { //如果不存在字典数据，则自动返回编码
		return code
	}
	data := itemMap.GetBean(code)
	upLayer := 0
	if dict.GetInt(consts.COL_DICT_TYPE) == consts.DIC_TYPE_TREE { //树形的判断向上获取层级数
		curLayer := data.GetInt("LEVEL")
		disLayer := dict.GetInt("DICT_NAME_LAYER")
		if disLayer > 0 {
			upLayer = disLayer
		} else {
			upLayer = curLayer - int(math.Abs(float64(disLayer)))
			if upLayer < 0 {
				upLayer = 0
			}
		}
	}
	fullName := strutils.NewStringBuilder(d.getCurLayerFullName(dict, data))
	for i := 0; i < upLayer; i++ { //循环获取父显示名称
		if data.Contains("PID") {
			data = itemMap.GetBean(data.GetStr("PID"))
			if data != nil {
				fullName = strutils.NewStringBuilder(d.getCurLayerFullName(dict, data) + "/").Append(fullName.ToString())
			} else {
				break
			}
		} else {
			break
		}
	}
	return fullName.ToString()
}

func (d *dictMgr) getCurLayerFullName(dict *bean.Bean, data *bean.Bean) string {
	if !dict.IsEmpty("DICT_DIS_FORMAT") {
		return util.BeanUtil.ReplaceValues(dict.GetStr("DICT_DIS_FORMAT"), data)
	} else {
		return data.GetStr("NAME")
	}
}
